// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#ifndef __H_MK_CAMERA__
#define __H_MK_CAMERA__

#include "mk_ref_counter.h"
#include "mk_view_frustum.h"

namespace MK3DE
{
	class MK3DE_API CCamera : public CRefCounter, public CViewFrustum
	{
	public:
		CCamera();
		~CCamera();

	public:
		//! Perspective projection.
		void SetAspectRatio(float aspect);
		void SetFOV(float fov);

		//! Orthographic projection.
		void SetWidth(float w);
		void SetHeight(float h);

		void SetViewNear(float n);
		void SetViewFar(float f);

		void SetPosition(D3DXVECTOR3& pos);
		void SetLookDirection(D3DXVECTOR3& dir);
		void SetUpDirection(D3DXVECTOR3& up);

		void EnablePerspectiveProjection(BOOL bEnable);
		BOOL IsPerspectiveProjection() { return _bPerspectiveProjection; }

		float GetAspectRatio() { return _aspectRatio; }
		float GetFOV() { return _fov; }

		float GetWidth() { return _width; }
		float GetHeight() { return _height; }

		float GetViewNear() { return _nearDis; }
		float GetViewFar() { return _farDis; }

		D3DXVECTOR3 GetUpDirection() { return D3DXVECTOR3(_matView._12, _matView._22, _matView._32); }
		D3DXVECTOR3 GetRightDirection() { return D3DXVECTOR3(_matView._11, _matView._21, _matView._31); }
		D3DXVECTOR3 GetLookDirection() { return D3DXVECTOR3(_matView._13, _matView._23, _matView._33); }

		D3DXVECTOR3 GetPosition() { return _position; }

		void MoveViewZ(float dis);
		void MoveViewX(float dis);
		void MoveAxisX(float dis);
		void MoveAxisY(float dis);
		void MoveAxisZ(float dis);
		void RotationViewX(float rad);
		void RotationAxisY(float rad);

		void GetPickRay(/* out */ D3DXVECTOR3& origPos, /* out */ D3DXVECTOR3& dir, D3DXVECTOR2& pos2D, DWORD width, DWORD height);

		void Update(DWORD dt);

		const D3DXMATRIX& GetViewMatrix() const       { return _matView;      }
		const D3DXMATRIX& GetProjMatrix() const       { return _matProj;      }
		const D3DXMATRIX& GetViewProjMatrix() const   { return _matViewProj ; }

		void ProjectPoint(/* out */ D3DXVECTOR2& outPos, D3DXVECTOR3& point, DWORD width, DWORD height);

	private:
		void __RecalculateViewMatrix();
		void __RecalculateProjMatrix();

	private:
		D3DXVECTOR3    _position;
		D3DXVECTOR3    _lookDirection;
		D3DXVECTOR3    _upDirection;

		//! Perspective projection.
		float _aspectRatio;
		float _fov;

		//! Orthographic projection.
		float _width;
		float _height;

		float _nearDis;
		float _farDis;

		BOOL _bPerspectiveProjection;

		D3DXMATRIX    _matView;
		D3DXMATRIX    _matProj;
		D3DXMATRIX    _matViewProj;

		BOOL _viewDirty;
		BOOL _projDirty;
	}; 
};

#endif // __H_MK_CAMERA__

